/**********************************************
  ECE 479 Winter 2010 
  Shrodinger's Cat 
  esra_module.cpp

  Function definitions for the module

**********************************************/

#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include "esra_module.h" // esra module header file

#include <time.h>    // Timer definitions used for nanotime

#include <sys/types.h>	// for multi-process programming

int (*valarray)[NUMCOL];	// 2-D array (numframe x NUMCOL)

				// for position values for each servo
int numframe;			// number of frames to be read

int esra(char *argv[])
{
	int i,j,k,l;		// loop control variable
	int fd;			// port descriptor for ttyS01

	char *args[4];		// arguments for execv call for play
	
	short sync = SYNCSSC;	// synchronization with Mini SSC
	short servo = 0;	// servo number
	short pos = 0;		// servo position 0~255
	short init = INITPOS;	// initial position
	
	
	args[0] = PLAYERPATH;		// path to the player
	args[1] = argv[1];		// name of .wav file
	args[2] = "-q";			//'quiet' option for sox player = "-q";
	args[3] = 0;			// null-terminate the array

	char buf[100];

	pid_t pid, pid1, pid2;		// Process Id structure declaration
	int status;			// Status indicator for the process

	read_csv_file(argv[0]); // Read servo position files

	pid = fork();			// Create a child process

	if(pid == 0)			// If this is the child process,  
	{				// play the sound file
		#ifdef DEBUG
			sprintf(buf, "\nPLAY PID?%d\n",pid);
			write(1,buf,strlen(buf));
		#endif
		execv(PLAYERPATH, args);

		exit(1);
	}
	else				// If it is the parent process, 
	{				// send the position values to the servo
		fd = open_port();	// Open serial port
		set_pos_initial(fd);	// Put servos to the initial position 127
		set_pos(fd);		// Drive servos	
		set_pos_initial(fd);	// Return servos to the initial position
		close(fd);		// Close serial port
	}

	pid1 = wait(&status);		// Wait until all processes are over

	return 0;
}


// Open .csv file provied by command line argument
// and load servo postion values to the 2D array
// valarray[numframes][NUMCOL]int read_csv_file(char *argv)

int read_csv_file(const char *argv)
{

	int i, j;	// loop control variables
	char ch[10];	// used to read delimiters
	char buf[100];	// used to read a line in frame count loop

	FILE *file = fopen( argv, "r" ); // open .csv file

	while(!feof(file))	// count the number of frames
	{
		fscanf(file, "%s\n", buf);
		++numframe;
	}
	rewind(file);		// return pointer back to the beginning

	numframe /= NUMCOL;

	valarray = malloc(numframe * NUMCOL * sizeof(int)); // allocate memory
				// for the 2D array
  	
  	#ifdef DEBUG
		printf("\nNumberof frames:%d", numframe);
	#endif

	while(!feof(file))	// Load position values to valarray
	{
		for (i=0; i < numframe; ++i)
		{
			for (j=0; j < NUMCOL; ++j)
			{
				fscanf(file, "%d", &(valarray[i][j]));
				fscanf(file, "%s", ch);
				
				#ifdef DEBUG
					printf("\nvalarray = %d", valarray[i][j]);
				#endif
			}
		}
	}

	fclose(file);		// Close the file

	return 0;
}

// Put servos into the initial position 

int set_pos_initial(int fd)
{
	short sync = 255;	// synchronization with Mini SSC
	short servo = 0;	// servo number
	short init = 127;	// initial position

	int j;
	
	for (j=0; j < NUMCOL; ++j) // Set servos to the initial position
	{
		servo = j;	// Servo #

		write(fd,&sync,1);
		write(fd,&servo,1);
		write(fd,&init,1);
	}
	
	return 0;
}	

// Send servo position values

int set_pos(int fd)
{
	int i,j,k,l;		// loop control variable

	short sync = 255;	// synchronization with Mini SSC
	short servo = 0;	// servo number
	short pos = 0;		// position value
	
	struct timespec t, rem;	// timer
	t.tv_sec = 0;
	t.tv_nsec = FRAMEDELAY; 	// 0.033 sec (33 000 000 nsec) delay
	
	for (i=0; i < numframe; ++i)
	{
		for (j=0; j < NUMCOL; ++j)
		{
			servo = j;
			pos = valarray[i][j];
			
			#ifdef DEBUG
				printf("\n valarray[%d][%d]=%d ",i,j, valarray[i][j]);
				printf("\n servo = %d, pos = %d", servo, pos);
			#endif
			
			if(pos >= 0)
			{
				write(fd,&sync,1);	// send sync signal
				write(fd,&servo,1);	// send servo #
				write(fd,&pos,1);	// send position value
			}	
		}

			#ifdef NANOTIME
				nanosleep(&t, &rem);	// Add delay defined as FRAMEDELAY
			#else
				for (k=0; k < 10000; ++k)	//software loop added for timing
				{
					for(l=0; l < 450; ++l);
				}
			#endif
		
		#ifdef DEBUG
			printf("\n===========================");
		#endif
			
	}
	
	return 0;
}


// Following codes generated by modifying POSIX serial programming
// tutorial from the following link
// http://www.easysw.com/~mike/serial/serial.html

/*
* 'open_port()' - Open serial port 1.
*
* Returns the file descriptor on success or -1 on error.
*/

int open_port(void)
{
	int fd; /* File descriptor for the port */

	fd = open(PORT, O_RDWR | O_NOCTTY | O_NDELAY);
	
	if (fd == -1)
	{
		/*
		* Could not open the port.
		*/

		printf("open_port: Unable to open /dev/ttyS0 - ");
	}
	else

	fcntl(fd, F_SETFL, 0);
	
	/* Serial Port Configuration */

	struct termios options;		// Termios options declration

	tcgetattr(fd, &options);	// Get current attribute
	cfsetispeed(&options, BAUD);	// Set input baud rate
	cfsetospeed(&options, BAUD);	// Set ouput buad rate 
	
	options.c_cflag &= ~PARENB;	// 8N1 configuration
	options.c_cflag &= ~CSTOPB;
	options.c_cflag &= ~CSIZE;
	options.c_cflag |= CS8;

	tcsetattr(fd, TCSANOW, &options); //Set new attribute

	return fd;
}
